<!DOCTYPE html>
<html>
<head>
    <title>Physics Diagram - Pulley with Sliding Ring</title>
</head>
<body>
    <canvas id="physicsCanvas" width="500" height="500"></canvas>
    <script>
        const canvas = document.getElementById('physicsCanvas');
        const ctx = canvas.getContext('2d');

        // Style settings
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 1.5;
        ctx.lineCap = 'round';

        /**
         * Draws an arrow on the canvas context.
         * @param {CanvasRenderingContext2D} ctx - The canvas context.
         * @param {number} fromx - The starting x-coordinate.
         * @param {number} fromy - The starting y-coordinate.
         * @param {number} tox - The ending x-coordinate.
         * @param {number} toy - The ending y-coordinate.
         */
        function drawArrow(ctx, fromx, fromy, tox, toy) {
            const headlen = 8; // length of head in pixels
            const dx = tox - fromx;
            const dy = toy - fromy;
            const angle = Math.atan2(dy, dx);
            ctx.beginPath();
            ctx.moveTo(fromx, fromy);
            ctx.lineTo(tox, toy);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(tox, toy);
            ctx.lineTo(tox - headlen * Math.cos(angle - Math.PI / 6), toy - headlen * Math.sin(angle - Math.PI / 6));
            ctx.moveTo(tox, toy);
            ctx.lineTo(tox - headlen * Math.cos(angle + Math.PI / 6), toy - headlen * Math.sin(angle + Math.PI / 6));
            ctx.stroke();
        }
        
        /**
         * Draws text with a subscript.
         * @param {CanvasRenderingContext2D} ctx - The canvas context.
         * @param {string} text - The main text.
         * @param {string} sub - The subscript text.
         * @param {number} x - The x-coordinate.
         * @param {number} y - The y-coordinate.
         * @param {string} font - The font for the main text.
         * @param {string} subFont - The font for the subscript.
         */
        function drawTextWithSubscript(ctx, text, sub, x, y, font, subFont) {
            ctx.font = font;
            const textMetrics = ctx.measureText(text);
            ctx.fillText(text, x, y);
            ctx.font = subFont;
            ctx.fillText(sub, x + textMetrics.width * 0.85, y + 5);
        }

        // --- Main Drawing ---

        // Define coordinates and dimensions
        const cx = 250;
        const cy = 130;
        const pulleyRadius = 60;
        const ceilingY = 50;

        // 1. Draw Ceiling
        ctx.beginPath();
        ctx.moveTo(cx - 160, ceilingY);
        ctx.lineTo(cx + 160, ceilingY);
        ctx.stroke();
        // Hatching lines for the ceiling
        const hatchLength = 15;
        const hatchSpacing = 15;
        ctx.lineWidth = 1;
        for (let i = cx - 160; i < cx + 160; i += hatchSpacing) {
            ctx.beginPath();
            ctx.moveTo(i, ceilingY);
            ctx.lineTo(i + hatchLength, ceilingY - hatchLength);
            ctx.stroke();
        }
        ctx.lineWidth = 1.5;

        // 2. Draw Pulley Support
        ctx.beginPath();
        ctx.rect(cx - 10, ceilingY, 20, cy - ceilingY);
        ctx.stroke();
        
        // 3. Draw Pulley
        ctx.beginPath();
        ctx.arc(cx, cy, pulleyRadius, 0, 2 * Math.PI);
        ctx.fillStyle = 'white'; // Fill to hide parts behind it
        ctx.fill();
        ctx.stroke();
        // Axle at the center
        ctx.beginPath();
        ctx.arc(cx, cy, 7, 0, 2 * Math.PI);
        ctx.stroke();
        // Label 'O' for the center
        ctx.fillStyle = 'black';
        ctx.font = 'italic 22px Times New Roman';
        ctx.fillText('O', cx + 12, cy + 10);
        
        // 4. Draw Radius 'r'
        const rAngle = (180 + 45) * Math.PI / 180; // Pointing down and left
        const rEndX = cx + pulleyRadius * Math.cos(rAngle);
        const rEndY = cy + pulleyRadius * Math.sin(rAngle);
        drawArrow(ctx, cx, cy, rEndX, rEndY);
        // Label 'r'
        ctx.fillText('r', cx - 40, cy - 25);

        // 5. Draw Rope
        ctx.beginPath();
        const ropeLeftX = cx - pulleyRadius;
        const ropeRightX = cx + pulleyRadius;
        // Left vertical segment
        ctx.moveTo(ropeLeftX, cy);
        ctx.lineTo(ropeLeftX, 300);
        // Right vertical segment
        ctx.moveTo(ropeRightX, cy);
        ctx.lineTo(ropeRightX, 380);
        // Arc over the pulley
        ctx.arc(cx, cy, pulleyRadius, Math.PI, 2 * Math.PI);
        ctx.stroke();

        // 6. Draw Block m1
        const m1Width = 70;
        const m1Height = 50;
        const m1X = ropeLeftX - m1Width / 2;
        const m1Y = 250;
        // Draw block body (filled to hide rope behind)
        ctx.beginPath();
        ctx.rect(m1X, m1Y, m1Width, m1Height);
        ctx.fillStyle = 'white';
        ctx.fill();
        ctx.stroke();
        // Redraw rope connecting to the block
        ctx.beginPath();
        ctx.moveTo(ropeLeftX, cy);
        ctx.lineTo(ropeLeftX, m1Y);
        ctx.stroke();
        // Cross-hatching pattern for m1
        ctx.save();
        ctx.beginPath();
        ctx.rect(m1X, m1Y, m1Width, m1Height);
        ctx.clip();
        ctx.lineWidth = 1;
        const step = 8;
        for (let i = m1X - m1Height; i < m1X + m1Width; i += step) {
            // Lines with slope 1 (\)
            ctx.beginPath();
            ctx.moveTo(i, m1Y);
            ctx.lineTo(i + m1Height, m1Y + m1Height);
            ctx.stroke();
            // Lines with slope -1 (/)
            ctx.beginPath();
            ctx.moveTo(i, m1Y + m1Height);
            ctx.lineTo(i + m1Height, m1Y);
            ctx.stroke();
        }
        ctx.restore();
        ctx.lineWidth = 1.5;
        // Label for m1
        const m1LabelX = m1X + 25;
        const m1LabelY = m1Y + m1Height + 25;
        drawTextWithSubscript(ctx, 'm', '1', m1LabelX, m1LabelY, 'italic 22px Times New Roman', 'italic 16px Times New Roman');

        // 7. Draw Ring m2
        const m2Width = 60;
        const m2Height = 25;
        const m2X = ropeRightX - m2Width / 2;
        const m2Y = 280;
        // Draw ring body (filled to hide rope behind)
        ctx.beginPath();
        ctx.rect(m2X, m2Y, m2Width, m2Height);
        ctx.fillStyle = 'white';
        ctx.fill();
        ctx.stroke();
        // Internal detail lines
        ctx.beginPath();
        ctx.moveTo(m2X + m2Width / 3, m2Y);
        ctx.lineTo(m2X + m2Width / 3, m2Y + m2Height);
        ctx.moveTo(m2X + 2 * m2Width / 3, m2Y);
        ctx.lineTo(m2X + 2 * m2Width / 3, m2Y + m2Height);
        ctx.stroke();
        // Redraw rope segment inside the ring
        ctx.beginPath();
        ctx.moveTo(ropeRightX, m2Y);
        ctx.lineTo(ropeRightX, m2Y + m2Height);
        ctx.stroke();
        // Label for m2
        const m2LabelX = m2X;
        const m2LabelY = m2Y - 10;
        drawTextWithSubscript(ctx, 'm', '2', m2LabelX, m2LabelY, 'italic 22px Times New Roman', 'italic 16px Times New Roman');

        // 8. Draw Acceleration a2
        const a2ArrowX = ropeRightX + 45;
        const a2ArrowYStart = m2Y;
        const a2ArrowYEnd = m2Y + m2Height + 20;
        drawArrow(ctx, a2ArrowX, a2ArrowYStart, a2ArrowX, a2ArrowYEnd);
        // Label for a2
        const a2LabelX = a2ArrowX - 30;
        const a2LabelY = a2ArrowYStart + 5;
        drawTextWithSubscript(ctx, 'a', '2', a2LabelX, a2LabelY, 'italic 22px Times New Roman', 'italic 16px Times New Roman');
        
        // 9. Draw Caption
        ctx.fillStyle = 'black';
        ctx.font = '22px "KaiTi"'; // A common font for Chinese characters in textbooks
        ctx.textAlign = 'center';
        ctx.fillText('习题 1-28 图', canvas.width / 2, 450);

    </script>
</body>
</html>